;;;我们不仅要关注值，也要关注时序
;;;we have to think about not only about values, but about time
 
;;计算一棵树中奇数的平方和
(define (sum-odd-squares tree)
  (if (leaf-node? tree)
      (if (odd? tree)
          (square tree)
          0)
      (+ (sum-odd-squares (left-branch tree))
         (sum-odd-squares (right-branch tree)))))
 
 
;;寻找前n个斐波那契数中的奇数
(define (odd-fibs n)
  (define (next k)
    (if (> k n)
        '()
        (let ((f (fib k)))
          (if (odd? f)
              (cons f (next (1+ k)))
              (next (1+ k))))))
  (next 1))
;;signal processing
;;;enumeriters leaves ---> filter odd? ---> map square ---> acc + 0
;;;enum interval -----> map fib ---> filter odd? ----> acc cons '()
 
;;;going back to this fundamental principle of computer science
;;;that in order to control something, you need the name of it
 
;;;流是一种数据抽象 stream is a data abstraction
;;;既然是一种数据抽象，所以先说明它的构造函数和选择函数是什么
(cons-stream x y)
(head s)
(tail s)
(head (cons-stream x y)) --> x
(tail (cons-stream x y)) --> y
;;;the-empty-stream
 
 
;;;abstraction layer
;;;abstraction barrier
 
 
(define (map-stream proc s)
  (if (empty-stream? s)
      the-empty-stream
      (cons-stream (proc (head s))
                   (map-stream proc (tail s)))))
 
(define (filter pred s)
  (cond ((empty-stream? s) the-empty-stream)
        ((pred (head s)) (cons-stream (head s) (filter pred
                                                       (tail s))))
        (else (filter pred (tail s)))))
 
;;;累积函数
;;;将流中的每个元素，按照combiner累积起来
(define (accumulate combiner init-val s)
  (if (empty-stream? s)
      init-val
      (combiner (head s)
                (accumulate combiner init-val (tail s)))))
 
;;;将树上的叶子结点append起来，成为一个流
(define (enumerate-tree tree)
  (if (leaf-node? tree)
       (cons-stream tree
                    the-empty-stream)
      (append-streams
       (enumerate-tree
        (left-branch tree))
       (enumerate-tree
        (right-branch tree)))))
 
;;;将两个流合并成一个流
(define (append-streams s1 s2)
  (if (empty-stream? s1)
      s2
      (cons-stream
       (head s1)
       (append-streams (tail s1)
                       s2))))
 
(define (enum-interval low high)
  (if (> low high)
       the-empty-stream
       (cons-stream
        low
        (enum-interval (+ 1 low) high))))
 
 
(define (sum-odd-squares tree)
  (accumulate
   +
   0
   (map square
        (filter odd
                (enumerate-tree tree)))))
 
(define (odd-fibs n)
  (accumulate
   cons
   '()
   (filter odd
           (map fib
                (enum-interval 1 n)))))
;;;重点：
;;;we're establishing conventional interfaces
 
 
 
;;;============================================================
;;;难的是accumulate
;;;map filter accumulate
 
 
;;;flatten返回值为一个流
;;;一个其中的每个元素都是流的流
(define (flatten stream-of-stream)
  (accumulate append-streams the-empty-stream stream-of-stream))
;;;依次对每个子流进行append
;;;((a b c ... ) (1 2 3 ... ) (A B C ... ) ... )变为
;;;(a b c ... 1 2 3 ... A B C ... ... )
;;;第一个子流s1，append第二个子流s2，append第三个子流s3，...
;;;+++++把所有的元素从子流中提取出来，把它们串接在一起+++++
 
 
;;其中f入参为一个元素，输出为一个流，也就是一个产生流的procedure
;;返回值也是一个流
(define (flatmap f s)
  (flatten (map f s)))
;;;flatmap就是flatten和map的结合
 
 
;;;返回值是一个流
(collect <result> <第一个流的范围，第二个流的范围> <filter>)
;;;============================================================
 
 
;;;0<j<i<=n，并且i+j为prime
;;;将1到n中的每个数字，变成一个流
;;;1到n本身就是个流，也就是(flatmap f s)
;;;这样就变成了流的流stream-of-stream，然后传递给flatten
;;;对1到n中的每个i，生成一个流，比如i为3，即(1 2 3)，则变成((3 2) (3 1))
(flatmap
 (lambda (i) ;;;对每一个i进行map
   (map (lambda (j) (list i j))
        (enum-interval 1 (-1+ i))))
 (enum-interval 1 n))
 
;;;(2 1)的car为2，cdr为(1)，cadr为1
;;;所以这里为cadr
(filter
 (lambda (p)
   (prime? (+ (car p) (cadr p))))
 (flatmap ... ))
 
(define (prime-sum-pairs n)
  (map
   (lambda (p)
     (list (car p) (cadr p) (+ (car p) (cadr p))))
   (filter ... )))
 
;;;总结：
;;;思路：
;;;1.将1到n的每个数字，映射为流(i j)，通过(flatmap f s)
;;;2.过滤stream-of-stream中的和为prime的元素
;;;3.将结果在映射为(i j i+j)
 
 
 
;;;通过使用flatmap，我们可以实现其他语言中的嵌套循环
;;;by using flatmaps, we can do what would correspond to
;;;nested loops in most other languages
 
 
;;;引进collect，用来代表特定顺序的flatmap和filter操作
;;;collect is for that nest of flatmaps and filters arranged in that
;;;particular way
(define (prime-sum-pairs n)
  (collect
   (list i j (+ i j)) ;;;对应结果
   ((i (enum-interval 1 n))
    (j (enum-interval 1 (-1+ i)))) ;;;对应flatmap
   (prime? (+ i j)))) ;;;对应filter
 
 
;;;嵌套的flatmap
 
 
;;;八皇后问题
;;;backtracking search
;;;过于关注时间
;;;this program is too inordinately concerned with time
;;;什么是时间？时间就是step
 
;;;在<rest-of-positions>这些位置已经放置棋子的条件下，
;;;在<row>行<column>列放置棋子是否安全
(safe? <row> <column> <rest-of-positions>)
 
 
 
;;;不把这颗树看做是逐步生成的
;;;而是假设所有的东西都已经生成好了
;;;假设k-1层已经生成好了，现在要生成第k层
;;;递归策略
;;;最终结果是个流
 
 
;;;size行的前k列
(define (queens size)
  (define (fill-cols k) ;;;填充第k列
    (if (= k 0)
        (singleton empty-board)
        (collect ... )))
  (fill-cols size))
 
(collect
 (adjoin-position try-row
                  k
                  rest-queens)
 ((rest-queens (fill-cols (-1+ k))) ;;;k-1列的所有放置方法
  (try-row (enum-interval 1 size)))
 (safe? try-row k rest-queens))
 
;;;总结：
;;;1.编写子过程，填充第k列，(fill-cols k)，是一个递归的，从第8列，到第7列，到。。。
;;;2.收集一些东西，找出k-1列的所有的放置，以及第k列的所有的可放置位置（即：1到8）
;;;3.过滤出为安全的位置
;;;最后得到结果流
 
 
;;;组合程序的方法
;;;find the second prime between 10000 and 1000000
(head
 (tail
  (filter prime? (enum-interval 10000 1000000))))
 
;;其中(enum-interval 10000 1000000)就是：
(cons 10000
      (delay (enum-interval 10001 1000000)))
 
 
;;;每个盒子代表了一个集合
;;;interval             filter
;;;10000     -------->  prime? ------->
;;;1000000
 
;;;stream are not list
;;;流不是表
 
;;;能够增量式的计算自己，一种按需的数据结构
;;;we want to arrange for a stream to be a data structure
;;;that sorts of computes itself incrementally
;;;sort of on-demand data structure
 
;;;本质：数据与过程之间，并没有明显界限
;;;流就是一种用过程表示的数据，特别是tail部分
;;;tail部分是一个无参过程(lambda () ... )
 
(cons-stream x y) ---> (cons x (delay y))
(head s) --> (car s)
(tail s) --> (force (cdr s)) ;;;(cdr s) --> (delay y)，而不是((delay y))，因为是pair，而不是list
 
 
(define (enum-interval low high)
  (if (> low high)
       the-empty-stream
       (cons-stream
        low
        (enum-interval (+ 1 low) high))))
(head (tail (filter prime? (enum-interval 10000 100000000))))
                           ;;;这部分相当于，因为low不大于high
                           (cons-stream 10000 (enum-interval 10001 100000000))
                           即：(cons 10000 (delay (enum-interval 10001 100000000)))
            (filter prime? (tail (cons 10000 (delay (enum-interval 10001 100000000))))) ;;;force this promise
                           即：(force (delay (enum-interval 10001 100000000)))
                           即：(enum-interval 10001 100000000) 
                           即：(cons-stream 10001 (enum-interval 10002 100000000))
                           即：(cons 10001 (delay (enum-interval 10002 100000000)))
                           ...
                           直到：(cons 10009 (delay (enum-interval 10010 100000000))) 找到第一个质数
                           然后再找第二个
 
 
;;;delay ---> 产生一个promise
;;;即：将<exp>的立即求值，转变为lambda，因为lambda不会立即求值
(delay <exp>) ---> (lambda () <exp>)
(force p) ---> (p) ;;;p为promise
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(force p) --> (p)
(force (delay p)) ---> (p)
((delay p))
((lambda () p))
(p)
((lambda () ... )) ---> (...)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;;;de-couple
 
;;;如果一个流是通过(cons-stream a (cons-stream b ... ))，不停的cons-stream得到的
;;;(tail (tail (tail ... )))
;;;修改delay的定义
(delay <exp>):
(memo-proc
 (lambda ()
   <exp>))
 
 
;;接受一个无参过程
(define (memo-proc proc)
  (let ((already-run? nil) (result nil))
    (lambda ()
      (if (not already-run?)
          (sequence
            (set! result (proc))
            (set! already-run? (not nil))
            result)
          result))))
 
;;;比如，已经知道了(tail stream)了
;;;那么，再次计算(tail (tail stream))时，内部的(tail stream)就不用再次计算了
 
;;;我们把数据结构组织的像一个过程
;;;we've written data structures that, in fact, are sort of like procedures.
;;;参考资料：
;;; https://github.com/xavier/sicp-notes/blob/master/lecture_06a.md
;;; https://chowdera.com/2021/11/20211129225341901Q.html
;;; https://people.eecs.berkeley.edu/~bh/ssch8/higher.html
;;; https://mitpress.mit.edu/sites/default/files/sicp/code/ch3.scm
;;;0<J<I<=N,取其中和为prime的组合
;;;将1到n的流,映射为 流的流
(flatmap
 (lambda (i)
   (map (lambda (j) (list i j)) (enum-interval 1 (- i 1))))
 (enum-interval 1 n))
;;;过滤出其中的prime
(filter
 (lambda (p)
   (prime? (+ (car p) (cadr p))))
 (flatmap ... ))
;;;将结果映射为(i j (i+j))
(map (lambda (x)
       (list (car x) (cadr x) (+ (car x) (cadr x))))
     (filter ...))
;;;改为collect的方式
(collect (list i j (+ i j))
         ((i (enum-interval 1 n))
          (j (enum-interval 1 i)))
         (prime? (+ i j)))
;;;八皇后问题
(define (queens size)
  ;;;递归填充第k列,k为8,7,6,。。。1,0
  (define (fill-cols k)
    (if (= k 0)
        (singleton empty-board)
        ;;;收集第k列的所有可能位置
        (collect ... )))
  (fill-cols size))
(collect
 ;;;结果
 (adjoin-position row k rest-queens)
 ;;;流
 ;;;1.已经存在的集合或者叫流,也就是填满第k-1列时,已经放置的位置
 ((rest-queens (fill-cols (- k 1)))
  ;;;2.row的可选集合或者叫流
  (row (enum-interval 1 n)))
 ;;;过滤
 (safe? row k rest-queens))
(cdr '(a b)) ;;;'(a b)是(list a b),而不是(cons a b)
(car '(a b))
(cdr '(x (delay y))) ;;;'(x (delay y))是(list x (delay y)),而不是(cons x (delay y))
 
(cdr (cons 'a 'b)) ;;; ---> b
 
(cdr (cons 'x (lambda () (+ 1 2))))
((cdr (cons 'x (lambda () (+ 1 2)))))
 
 
;;;https://www.thinbug.com/q/942580
;;;https://courses.cs.washington.edu/courses/cse341/04wi/lectures/14-scheme-quote.html
;;;google scheme run quote lambda
 
 
;;; pair:
;;;   |--------|-------|
;;;   |    a   |  b    |
;;;   |        |       |
;;;   |--------|-------|
;;;
;;;
;;; list:
;;;  |------|-------|        |------|---|
;;;  |   a  |   ----|------->|  b   | / |
;;;  |      |       |        |      |/  |
;;;  |------|-------|        |------|---|      
;;;
;;;
;;;  pair:
;;;  |------|-------|        |------|-----|
;;;  |   a  |   ----|------->|  b   | c   |
;;;  |      |       |        |      |     |
;;;  |------|-------|        |------|-----|
;;;
